/**
* Project: yui3-common-mybatisx
 * Class MybatisXMLMapperBuilder
 * Version 1.0
 * File Created at 2019年1月21日
 * $Id$
 * author yuyi
 * email 1060771195@qq.com
 */
package yui.comn.mybatisx.core;

import java.io.InputStream;
import java.util.Map;

import org.apache.ibatis.builder.BaseBuilder;
import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.parsing.XPathParser;
import org.apache.ibatis.session.Configuration;

/**
 * <p>
 * MyBatis对xml和注解，解析类
 * <p>
 * 
 * @author yuyi (1060771195@qq.com)
 */
public class InjectorMapperBuilder extends BaseBuilder {

    private final XPathParser parser;
    private final MapperBuilderAssistant builderAssistant;
    private final Map<String, XNode> sqlFragments;
    private final String resource;

    public InjectorMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments, String namespace) {
      this(inputStream, configuration, resource, sqlFragments);
      this.builderAssistant.setCurrentNamespace(namespace);
    }

    public InjectorMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
      this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
          configuration, resource, sqlFragments);
    }

    private InjectorMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
      super(configuration);
      this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
      this.parser = parser;
      this.sqlFragments = sqlFragments;
      this.resource = resource;
    }

    public void parse() {
      if (!InjectorConfig.isInjectorResource(resource)) {
        configurationElement(parser.evalNode("/mapper"));
        bindMapperForNamespace();
      }

      // parsePendingResultMaps();
      // parsePendingCacheRefs();
      // parsePendingStatements();
    }

    public XNode getSqlFragment(String refid) {
      return sqlFragments.get(refid);
    }

    private void configurationElement(XNode context) {
      try {
        String namespace = context.getStringAttribute("namespace");
        if (namespace == null || namespace.equals("")) {
          throw new BuilderException("Mapper's namespace cannot be empty");
        }
        builderAssistant.setCurrentNamespace(namespace);
      } catch (Exception e) {
        throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
      }
    }

//    private void parsePendingResultMaps() {
//      Collection<ResultMapResolver> incompleteResultMaps = configuration.getIncompleteResultMaps();
//      synchronized (incompleteResultMaps) {
//        Iterator<ResultMapResolver> iter = incompleteResultMaps.iterator();
//        while (iter.hasNext()) {
//          try {
//            iter.next().resolve();
//            iter.remove();
//          } catch (IncompleteElementException e) {
//            // ResultMap is still missing a resource...
//          }
//        }
//      }
//    }
//
//    private void parsePendingCacheRefs() {
//      Collection<CacheRefResolver> incompleteCacheRefs = configuration.getIncompleteCacheRefs();
//      synchronized (incompleteCacheRefs) {
//        Iterator<CacheRefResolver> iter = incompleteCacheRefs.iterator();
//        while (iter.hasNext()) {
//          try {
//            iter.next().resolveCacheRef();
//            iter.remove();
//          } catch (IncompleteElementException e) {
//            // Cache ref is still missing a resource...
//          }
//        }
//      }
//    }
//
//    private void parsePendingStatements() {
//      Collection<XMLStatementBuilder> incompleteStatements = configuration.getIncompleteStatements();
//      synchronized (incompleteStatements) {
//        Iterator<XMLStatementBuilder> iter = incompleteStatements.iterator();
//        while (iter.hasNext()) {
//          try {
//            iter.next().parseStatementNode();
//            iter.remove();
//          } catch (IncompleteElementException e) {
//            // Statement is still missing a resource...
//          }
//        }
//      }
//    }

    private void bindMapperForNamespace() {
      String namespace = builderAssistant.getCurrentNamespace();
      if (namespace != null) {
        Class<?> boundType = null;
        try {
          boundType = Resources.classForName(namespace);
        } catch (ClassNotFoundException e) {
          //ignore, bound type is not required
        }
        if (boundType != null) {
            
            //start 先进行自定义Mapper注入
            InjectorMapperRegistry registry = new InjectorMapperRegistry(configuration);
            // if (!registry.hasMapper(boundType)) {
            registry.addMapper(boundType);
            // }
            //end
            
        }
      }
    }

  }